package mslog

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"time"

	"gitee.com/yrwy/go-log"
	"gitee.com/yrwy/msgo/pkg/strs"
	"github.com/spf13/viper"
)

func NewWriter(logcfg string) (log.Logger, error) {
	v := viper.New()
	v.SetConfigFile(logcfg)
	err := v.ReadInConfig()
	if err != nil {
		fmt.Println("viper error:", err)
		return nil, err
	}
	var fmtopts []log.FormatterOption
	fmtopts = append(fmtopts, log.FProperties(log.LstdFlags|log.LineFeed))
	sv := v.Sub("format")
	if sv != nil {
		dtfmt := sv.GetString("datetime")
		t := time.Now()
		s := t.Format(dtfmt)
		_, err := time.Parse(dtfmt, s)
		if err == nil {
			fmtopts = append(fmtopts, log.FDatetimeLayout(dtfmt))
		}
	}
	fmter := log.NewTextFormatter(fmtopts...)
	logOpts := []log.LogOption{log.LogFormatter(fmter)}
	sv = v.Sub("console")
	var ws []log.LogWriter
	if sv != nil {
		level := sv.GetString("enable")
		lv := log.NewLevel(level)
		if lv != log.NOLOG {
			fmt.Println("console log level:", lv)
			ws = append(ws, log.NewConsoleWriter(log.LWLevel(lv), log.LWErrHandler(writerError)))
		}
	}
	sv = v.Sub("file")
	if sv != nil {
		level := sv.GetString("enable")
		lv := log.NewLevel(level)
		if lv != log.NOLOG {
			fmt.Println("file log level:", lv)
			var fileropts []log.FilerOption
			appname := os.Args[0]
			appname = filepath.Base(appname)
			if appname != "" {
				fileropts = append(fileropts, log.FilePrefex(appname))
			}
			s := sv.GetString("rootpath")
			if len(s) > 0 {
				fileropts = append(fileropts, log.FileRoot(s))
			}
			s = sv.GetString("maxfilesize")
			if len(s) > 0 {
				n := strs.ParseBytes(s)
				if n > 0 {
					fmt.Println("maxfilesize:", s, n)
					fileropts = append(fileropts, log.FileMaxSize(int(n)))
				}
			}
			n := sv.GetInt("maxsavedays")
			if n >= 0 {
				fileropts = append(fileropts, log.FileSaveDays(n))
			}
			fileropts = append(fileropts, log.FWFileCut(fileCut))
			filer, err := log.NewFiler(fileropts...)
			if err != nil {
				return nil, err
			}
			ws = append(ws, log.NewLogWriter(log.LWLevel(lv), log.LWithWriter(filer), log.LWErrHandler(writerError)))
		}
	}
	if len(ws) == 1 {
		logOpts = append(logOpts, log.LogSetWriter(ws[0]))
	} else if len(ws) > 1 {
		w := log.NewMultiWriter(ws...)
		logOpts = append(logOpts, log.LogSetWriter(w))
	} else {
		return nil, errors.New("no logger writer")
	}
	sv = v.Sub("log")
	if sv != nil {
		s := sv.GetString("cache")
		if len(s) > 0 {
			n := strs.ParseBytes(s)
			if n >= 0 {
				fmt.Println("log cache:", s, n)
				if n > 1024*1024*100 {
					n = 1024 * 1024 * 100 //100M
				}
				logOpts = append(logOpts, log.LogCache(int(n)))
			}
		}
	}
	//logOpts = append(logOpts, log.LogMustLevels(ERROR|FATAL))
	_logger := log.NewLogger(logOpts...)
	return _logger, nil
}

func writerError(w log.LogWriter, err error, msg string) {
	fmt.Sprintln(w, err, msg)
}

func fileCut(fn string) {
	log.Log(log.INFO, "log file cut:", fn)
}
